import json
import copy
import uuid
from typing import List
from typing import Union
from apis import api_routes
from sqlalchemy import desc
from sqlalchemy import and_
from models.course.course import Course
from flask import abort, g, request, jsonify
from security.decoration import certification
from models.facility.facility import Facility
from public.local import date_type
from datetime import datetime, timedelta
from models.product.routes import Routes
from models.order.tasks import Tasks
from models.product.aircraft import Aircraft
from models.course.detailed import Detailed
from models.product.repairs import Repairs
from public.contexts import context_logs


@api_routes.route("/repair", methods=["GET"])
@certification(auth=True, role=None)
def func_repair_get_api():
    """
    查询返修任务，有做分页，完成API开发
    http://127.0.0.1:8080/api/repair
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    "start"        string          开始时间, 默认今天前面30天时间  格式 %Y-%m-%d
    "finish"       string          结束时间，默认今天时间  格式 %Y-%m-%d
    "index"         int      ****  第几页，默认为1
    "size"          int      ****  每页数据多少, 默认每页10条数据
    "mark"          int[1、2、3]    查修种类[1是合格， 2是不合格， 3是报废的]， 默认为2
    "sequence"      string         产品SN，不支持模糊查询
    }
    :return:
        {'status': 200, 'data': resp}
    ---
    tags:
      - 返工工艺管理
    """
    index = request.args.get("index", default=1, type=int)
    size = request.args.get("size", default=10, type=int)
    start: Union[str, None] = request.args.get("start", default=None, type=str)
    finish: Union[str, None] = request.args.get("finish", default=None, type=str)
    mark = request.args.get("mark", default=2, type=int)
    sequence: Union[str, None] = request.args.get("sequence", default=None, type=str)

    if mark not in [0, 1, 2, 3]:
        abort(400)

    parameter: list = []

    if start is not None and len(start) > 0:
        parameter.append(Course.start >= datetime.strptime(start, "%Y-%m-%d"))

    if finish is not None and len(finish) > 0:
        arg1 = datetime.strptime(finish, "%Y-%m-%d") + timedelta(days=1) - timedelta(seconds=1)
        parameter.append(Course.start <= arg1)

    if mark is not None and mark == 1:
        parameter.append(Course.mark <= mark)
    elif mark is not None and mark != 1:
        parameter.append(Course.mark == mark)

    if sequence is not None and len(sequence) != 0:
        parameter.append(Course.sequence == sequence)

    count = g.session.query(Course.id).filter(and_(* parameter)).count()
    page: int = int((count / size) + 1) if (count / size) > int(count / size) else int(count / size)

    data: List[Course] = g.session.query(Course).filter(and_(* parameter)).order_by(Course.id).offset((index - 1) * size).limit(size).all()

    parm: dict = {0: "未加工完成", 1: "合格", 2: "不合格", 3: "报废"}
    rsp: list = []

    for index, itr in enumerate(data):
        db_aircraft: Aircraft = g.session.query(Aircraft).filter(Aircraft.id == itr.aircraft_id).first()
        db_task: Tasks = g.session.query(Tasks).filter(Tasks.id == itr.tasks_id).first()

        detailed: Detailed = g.session.query(Detailed).filter(and_(
                                Detailed.sequence == itr.sequence,
                                Detailed.status == 'f'
                            )).order_by(desc(Detailed.id)).first()
        ng_number: int = 0
        facility_name: Union[str, None] = None
        if detailed is not None:
            facility: Facility = g.session.query(Facility).filter(
                                    Facility.id == detailed.facility_id
                                ).first()
            facility_name = facility.name
            ng_number: int = g.session.query(Detailed.id).filter(and_(
                Detailed.facility_id == facility.id,
                Detailed.sequence == itr.sequence,
                Detailed.status == False
            )).count()

        mark_value: Union[str, None] = parm.get(itr.mark)
        finish_fmt_str: Union[str, None] = None
        if itr.finish is not None:
            finish_fmt_str = itr.finish.strftime("%Y-%m-%d %H:%M:%S")

        rework: bool = True if (itr.mark == 2 and itr.repair is not None) else False
        list_rts: list = []
        if rework is True:
            repair: dict = json.loads(itr.repair)
            routes: list = repair.get("data")

            for sequence_number, rts in enumerate(routes):
                data_rts: list = []
                data_rts.clear()
                db_rout: list = rts.get("ft_ids")
                for _, rt in enumerate(db_rout):
                    db_ft: Facility = g.session.query(Facility).filter(Facility.id == rt).first()
                    data_rts.append({
                        "facility_id": db_ft.id,
                        "sequence": sequence_number + 1,
                        "name": db_ft.name,
                        "serials": db_ft.serials,
                    })
                list_rts.append(data_rts)

        rsp.append({
            "course_id": itr.id,
            "sequence": itr.sequence,
            "start": itr.start.strftime("%Y-%m-%d %H:%M:%S"),
            "finish": finish_fmt_str,
            "mark": itr.mark,
            "mark2": mark_value,
            "message": itr.message,
            "aircraft": db_aircraft.aircraft,
            "task_name": db_task.name,
            "rework": 1 if rework else 0,
            "rework2": "是" if rework else "否",
            "repairs": copy.deepcopy(list_rts),
            "facility_name": facility_name,
            "error": detailed.error if detailed else None,
            "aircraft_id": db_aircraft.id,
            "ng_number": ng_number
        })

    doc: dict = {
        "course_id": "对应数据库ID",
        "message": "报废原因",
        "sequence": "产品SN",
        "start": "开始时间",
        "mark": "产品状态（未加工，合格，不合格，报废）",
        "finish": "结束时间",
        "aircraft": "机种名称",
        "task_name": "工单名称",
        "rework": "是否添加返工路径",
        "repairs": "返工路径",
        "facility_name": "异常工站",
        "error": "异常原因",
        "ng_number": "不合格次数"
    }
    return jsonify({'status': 200, 'data': rsp, "index": index, "size": size, "total": count, "page": page, "doc": doc})


@api_routes.route("/repair", methods=["PUT"])
@certification(auth=True, role=None)
def func_repair_put_api():
    """
    更新返修任务信息, 完成API开发
    http://127.0.0.1:8080/api/repair
    Content-Type=application/json
    methods=["PUT"]
    {
    "course_id"     int         ****  对应数据库ID
    "mark"          string            标记，[1是合格， 2是不合格， 3是报废的]
    "message"       string            报废信息备注
    "repairs"       array[json]       返工工艺路线  [{"ft_ids": [1]}, {"ft_ids": [2, 3]},{"ft_ids": [4]}, ....]
    }
    :return:
        {'status': 4000, 'msg': "不存在此数据，无法删除"}
        {'status': 4002, 'msg': "返修加工路径参数错误"}
        {'status': 4003, 'msg': "工序参数没有找到要绑定设备"}
        {'status': 4004, 'msg': "设备没有绑定PLC, 无法交互，禁止添加"}
        {'status': 4005, 'msg': "返修同一工序禁止添加重复设备"}
        {'status': 4006, 'msg': "相隔工序不能存在同一种设备"}
        {'status': 4007, 'msg': "标记返修，返修工艺路线不能为空!"}
        {'status': 4008, 'msg': "报废信息备注不能为空"}
        {'status': 200, 'msg': "更新完成"}
    ---
    tags:
      - 返工工艺管理
    """
    data: dict = request.get_json()
    course_id: int = data.get("course_id")
    mark: Union[int, None] = data.get("mark")
    message: Union[str, None] = data.get("message")
    repairs: Union[list, int, None] = data.get("repairs")

    if course_id is None or mark is None or int(mark) not in [1, 2, 3]:
        abort(400)
    mark: int = int(mark)

    course: Course = g.session.query(Course).filter(Course.id == course_id).first()
    if course is None:
        return jsonify({'status': 4000, "msg": "没有找到产品清单"})

    mark_bf = course.mark
    task: Tasks = g.session.query(Tasks).filter(Tasks.id == course.tasks_id).first()

    context_logs(name="更新返修任务信息", obsolescence=course.__repr__(), data=json.dumps(data))

    if mark is not None and mark != course.mark and mark in [1, 2, 3]:
        course.mark = mark

    if message is not None and course.mark == 3:
        course.message = message

    if repairs is not None:
        temp_repairs: list = []

        if not isinstance(repairs, list):
            g.session.rollback()
            return jsonify({'status': 4002, 'msg': "返修加工路径参数错误!"})

        for index, itr in enumerate(repairs):
            if not isinstance(itr, dict) or not isinstance(itr.get("ft_ids"), list):
                return jsonify({'status': 4001, 'msg': "返修加工路径参数错误"})
            ft_ids: list = itr.get("ft_ids")
            if len(ft_ids) == 0:
                return jsonify({'status': 4002, 'msg': "返修参数验证设备不能为空!"})
            for itr22 in ft_ids:
                db_ft: Union[Facility, None] = g.session.query(Facility).filter(Facility.id == itr22).first()
                if db_ft is None:
                    return jsonify({'status': 4003, 'msg': "返修参数没有找到要绑定设备，验证失败!"})
                if db_ft.uuid4 is None:
                    return jsonify({'status': 4004, 'msg': "返修设备没有绑定PLC, 无法交互，禁止添加"})

            if len(set(ft_ids)) != len(ft_ids):
                return jsonify({'status': 4005, 'msg': "返修同一工序禁止添加重复设备"})
            temp_repairs.append(ft_ids)

        for itr in range(1, len(temp_repairs)):
            now_date: list = temp_repairs[itr]
            before: list = temp_repairs[itr - 1]
            list3 = []
            for item in before:
                if item in now_date:
                    list3.append(item)
            if len(list3) != 0:
                return jsonify({'status': 4006, 'msg': "返修相隔工序不能存在同一种设备!"})

        course.repair = json.dumps({"data": repairs})

    if course.mark == 2 and course.repair is None:
        g.session.rollback()
        return jsonify({'status': 4007, 'msg': "标记返修，返修工艺路线不能为空!"})

    if course.mark == 3 and course.message is None:
        g.session.rollback()
        return jsonify({'status': 4008, 'msg': "报废信息备注不能为空"})

    if course.mark == 3:
        db_detailed: Union[Detailed, None] = g.session.query(Detailed).filter(
            Detailed.sequence == course.sequence
        ).order_by(desc(Detailed.id)).limit(1).offset(0).first()
        if db_detailed is not None:
            db_detailed.mark = 3

    if course.mark != mark_bf:
        course.session = uuid.uuid4()

        if course.mark == 1:
            detailed: List[Detailed] = g.session.query(Detailed).filter(and_(
                        Detailed.sequence == course.sequence,
                        Detailed.numbers == course.numbers
                    )).order_by(desc(Detailed.id)).all()
            for xxx in detailed:
                if xxx.status is False:
                    xxx.status = True
                if xxx.mark != 1:
                    xxx.mark = 1
        task.totals = g.session.query(Course.id).filter(and_(Course.mark >= 1, Course.tasks_id == task.id)).count()
        task.actual = g.session.query(Course.id).filter(and_(Course.mark == 1, Course.tasks_id == task.id)).count()

    # 返工工艺标志信号
    if course.mark == 2:
        course.session = uuid.uuid4()
        info: str = str({
            "repair": course.repair,
            "numbers": course.mark
        })
        context_logs(name="手动创建返工任务", obsolescence=course.sequence, data=info)

        # uuid_key = "queues-{}".format("7c9df6cc-b8f7-4cce-b9cb-f9bfd7527df5")
        # g.cache.rpush(uuid_key, json.dumps({"address": "DM4150", "type": "String", "value": course.sequence}))
        # g.cache.rpush(uuid_key, json.dumps({"address": "DM4118", "type": "Short", "value": 1}))
        # g.cache.expire(uuid_key, 8)

    g.session.commit()
    return jsonify({'status': 200, 'msg': "更新完成"})


@api_routes.route("/repair/template", methods=["PUT"])
@certification(auth=True, role=None)
def func_repair_template_put_api():
    """
    根据返工模板更新返修任务信息, 完成API开发
    http://127.0.0.1:8080/api/repair/template
    Content-Type=application/json
    methods=["PUT"]
    {
    "course_id"     int         ****  对应数据库ID
    "template_id"   int         ****  对应数据库ID
    "message"       string            日志记录
    }
    :return:
        {'status': 4000, "msg": "没有找到产品SN"}
        {'status': 4001, 'msg': "无法查询到模板号, 操作失败"}
        {'status': 200, 'msg': "更新完成"}
    ---
    tags:
      - 返工工艺管理
    """
    data: dict = request.get_json()
    course_id: int = data.get("course_id")
    template_id: int = data.get("template_id")
    t_message: Union[str, None] = data.get("message")

    if course_id is None or template_id is None:
        abort(code=400)

    db_course: Course = g.session.query(Course).filter(Course.id == course_id).first()
    if db_course is None:
        return jsonify({'status': 4000, "msg": "没有找到产品SN"})

    db_repair: Union[Repairs, None] = g.session.query(Repairs).filter(Repairs.id == template_id).first()
    if db_repair is None:
        return jsonify({'status': 4001, 'msg': "无法查询到模板号, 操作失败"})

    # ********************************************************************************
    if t_message is not None and len(t_message) > 0:
        db_detailed2: Union[Detailed, None] = g.session.query(Detailed).filter(and_(
                        Detailed.course_id == db_course.id,
                        Detailed.status == 'f'
                    )).order_by(desc(Detailed.id)).first()
        if db_detailed2 is not None:
            db_detailed2.error = t_message
    # ********************************************************************************
    db_course.mark = 2
    db_course.repair = db_repair.route
    db_course.session = uuid.uuid4()

    # uuid_key = "queues-{}".format("7c9df6cc-b8f7-4cce-b9cb-f9bfd7527df5")
    # g.cache.rpush(uuid_key, json.dumps({"address": "DM4150", "type": "String", "value": db_course.sequence}))
    # g.cache.rpush(uuid_key, json.dumps({"address": "DM4118", "type": "Short", "value": 1}))
    # g.cache.expire(uuid_key, 8)

    info: str = str({
        "db_course": {
            "mark": db_course.mark,
            "repair": db_course.repair,
            "numbers": db_course.mark
        },
        "db_repair": {
            "repair": db_repair.route
        }
    })
    context_logs(name="返工模板创建返工任务", obsolescence=db_course.sequence, data=info)
    g.session.commit()
    return jsonify({'status': 200, 'msg': "更新完成"})

